<template>
  <el-drawer
    :append-to-body="true"
    size="1000px"
    :wrapperClosable="false"
    :visible="show"
    @close="handleClose"
    :with-header="false"
  >
    <div class="components_container relative">
      <i @click="handleClose" class="el-icon-close"></i>
      <div class="talk_left transition_ease" :class="{'w_63 border_0':showTextBoolean}">
        <div class="top">
          <div class="ai_name">
            <div :class="{'w_0':showTextBoolean}" class="title transition_ease line_feed">元元</div>
            <img @click="showTextBoolean = !showTextBoolean" class="close_icon"
                 :class="{'rotate_z_180':showTextBoolean}" src="@/assets/image_ai/left_close.png" alt="加载失败"
            >
          </div>
          <div v-if="!showTextBoolean" v-loading="showConversationLoading && showCourseLoading">
            <div class="course_collect" v-if="$store.getters.roleId=='teacher'">
              <div class="tools_container" @click="showCourseListBoolean = !showCourseListBoolean">
                <div class="title">
                  <img class="icon" src="@/assets/image_ai/course_helper_icon.png" alt="加载失败">
                  课程助手
                </div>
                <img :class="{'rotate_z_180':showCourseListBoolean}" class="right_icon transition_ease"
                     src="@/assets/image_ai/up_icon.png" alt="加载失败"
                >
              </div>
              <div class="course_talk_list mt_12 transition_ease"
                   :class="{
                 'max_height_0':showCourseListBoolean,
                 'only_herf_height': showToolsBoolean && !showOtherListBoolean,
                 'only_herf_height2': !showToolsBoolean && !showOtherListBoolean,
                 'only_height':showOtherListBoolean && showToolsBoolean,
                 'only_height2':showOtherListBoolean && !showToolsBoolean
                 }"
              >
                <vuedraggable
                  @change="handleChange($event,1)"
                  class="flex"
                  ghost-class="custom_ghost"
                  v-model="courseHelperList"
                  group="site"
                  animation="300"
                >
                  <div @click="handleClickCourseItem(item)" class="talk_item"
                       :class="{'select_active':item.conversationId == conversationId}"
                       v-for="(item,index) in courseHelperList" :key="index"
                  >
                    <div class="talk_name">
                      <tooltip
                        position="top-start"
                        :text="item.courseName"
                        width="100%"
                      />
                    </div>
                  </div>
                </vuedraggable>
              </div>
            </div>
            <div class="course_collect">
              <div class="tools_container" @click="showOtherListBoolean = !showOtherListBoolean">
                <div class="title">
                  <img class="icon" src="@/assets/image_ai/other_helper_icon.png" alt="加载失败">
                  其他助手
                </div>
                <img :class="{'rotate_z_180':showOtherListBoolean}" class="right_icon transition_ease"
                     src="@/assets/image_ai/up_icon.png" alt="加载失败"
                >
              </div>
              <div class="other_talk mt_6 transition_ease"
                   :class="{
                 'max_height_0':showOtherListBoolean,
                 'only_herf_height': showToolsBoolean && !showCourseListBoolean,
                 'only_herf_height2': !showToolsBoolean && !showCourseListBoolean,
                 'only_height':showCourseListBoolean && showToolsBoolean,
                 'only_height2':showCourseListBoolean && !showToolsBoolean
                 }"
              >
                <div @click="handleClickNewTalk" class="new_talk w_all">
                  <img src="@/assets/image_ai/new_talk.png" alt="加载失败">
                  <div class="name">开启新对话</div>
                </div>
                <template v-if="conversationList.length>0">
                  <vuedraggable
                    @change="handleChange($event,2)"
                    class="flex"
                    ghost-class="custom_ghost"
                    v-model="conversationList"
                    group="site"
                    animation="300"
                  >
                    <div @dblclick.stop="changeName(item)" @click="handleClick(item)"
                         :class="{'select_active':item.conversationId == conversationId,'p_0':item.showRename}"
                         class="talk_item" v-for="(item,index) in conversationList" :key="index"
                    >
                      <div v-if="!item.showRename" class="talk_name">
                        <tooltip
                          position="top-start"
                          :text="item.title"
                          width="100%"
                        />
                      </div>
                      <div v-if="!item.showRename" class="btn">
                        <img @click.stop="delStream(item)" class="del_icon" src="@/assets/image_ai/del_icon.png"
                             alt="加载失败"
                        >
                      </div>
                      <div v-if="item.showRename" class="rename_ipt_content">
                        <el-input @blur="saveName(item)" class="rename_ipt" ref="renameRef" v-model="item.rename" placeholder="请输入标题"
                                  type="text"
                        ></el-input>
                      </div>
                    </div>
                  </vuedraggable>
                </template>
                <div v-else class="empty_box">暂无历史对话</div>
              </div>
            </div>
          </div>
        </div>
        <div class="bottom" v-if="!showTextBoolean">
          <div class="tools_container" @click="showToolsBoolean = !showToolsBoolean">
            <div class="title">
              <img class="icon" src="@/assets/image_ai/tools_icon.png" alt="加载失败">
              常用工具
            </div>
            <img :class="{'rotate_z_180':showToolsBoolean}" class="right_icon transition_ease"
                 src="@/assets/image_ai/up_icon.png" alt="加载失败"
            >
          </div>
          <div class="tools_btns transition_ease" :class="{'h_0':showToolsBoolean}">
            <div @click="routeTo(item)" class="item_btn" v-for="(item,index) in btns" :key="index">
              <img :src="item.icon" alt="加载失败">
              {{ item.title }}
            </div>
            <div style="font-size: 14px;color: #999999">更多工具正在开发中~</div>
          </div>
        </div>
      </div>
      <div class="talk_right" :class="{'max_width':!showTextBoolean}" v-loading="talkLoading">
        <div v-if="newTalk" class="say_hello">
          你好，很高兴见到你！
        </div>
        <template v-else>
          <div class="talk_title overTxt">
            {{ talkTitle }}
          </div>
          <div class="talk_content" ref="chatBox" @scroll="handleChatBoxScroll">
            <div v-for="(item,index) in messageList" :key="index">
              <!--   用户会话  -->
              <div class="user_chat" v-if="item.role=='user'">
                <div class="send_file_list" v-if="item.sendFileList">
                  <div @click="showFileDrawer(fileItem)" class="file_item shou" v-for="(fileItem,fileIndex) in item.sendFileList" :key="fileIndex">
                    <img class="icon" :src="fileItem.icon" alt="">
                    <div class="item_right">
                      <div class="name overTxt">{{ fileItem.name }}</div>
                      <div class="size">{{ fileItem.sizeText }}</div>
                    </div>
                  </div>
                </div>
                <div class="user_content">
                  <formula-renderer :content="item.content"/>
                </div>
              </div>
              <!--   AI会话  -->
              <div class="ai_chat" v-if="item.role=='assistant'">
                <img class="ai_avatar" src="@/assets/images/AI_smart_icon.png" alt="加载失败">
                <div>
                  <div class="ai_content line_feed">
                    <!--  联网搜索   -->
                    <div class="online_search" v-if="item.searchResults">
                      <div class="title">联网搜索</div>
                      <div @click="routeTo(searchItem)" :id="`ref_${searchIndex+1}`" class="search_item shou"
                           v-for="(searchItem,searchIndex) in item.searchResults" :key="searchIndex"
                      >
                        <div class="top line_feed">
                          <img class="img" :src="searchItem.icon?searchItem.icon:require('@/assets/images/AI_smart_icon.png')" alt="">
                          {{ searchItem.site_name ? searchItem.site_name : '---' }}
                        </div>
                        <div class="text line_feed">{{ searchItem.title ? searchItem.title : '---' }}</div>
                      </div>
                    </div>
                    <!--  深度思考   -->
                    <div class="deep_thinking" v-if="item.reasoningContent">
                      <div class="loading_title" v-if="showReasonLoading">深度思考
                        <img class="loading_img" src="@/assets/image_ai/loading_img.png" alt="">
                      </div>
                      <div class="title" v-else>深度思考</div>
                      <div class="content line_feed" v-html="item.reasoningContent"></div>
                    </div>
                    <!--   正常会话    -->
                    <div class="formula">
                      <formula-renderer class="common_text" :content="item.content"/>
                    </div>
                  </div>
                  <div class="ai_btns" v-if="index==messageList.length-1">
                    <div class="ai_copy" @click="copyText(item)">
                      <img src="@/assets/image_ai/ai_copy.png" alt="">
                    </div>
                    <div class="ai_copy" @click="refreshTalk(item,index)">
                      <img src="@/assets/image_ai/ai_refresh.png" alt="">
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div class="ai_chat" v-if="firstTalkLoading">
              <img class="ai_avatar" src="@/assets/images/AI_smart_icon.png" alt="加载失败">
              <div class="ai_content line_feed">
                <div class="common_text">
                  <img class="loading_img" src="@/assets/image_ai/loading_green.png" alt="">
                </div>
              </div>
            </div>
            <div style="flex: 1"></div>
            <div class="talk_bottom" id="scrollBottomId">
              <div v-if="!courseId" @click="handleClickNewTalk" class="new_talk">
                <img src="@/assets/image_ai/new_talk.png" alt="加载失败">
                <div class="name">开启新对话</div>
              </div>
            </div>
          </div>
        </template>
        <!--   对话框     -->
        <div class="ipt_content relative transition_ease" :class="{'border_green':showBorder,'mb_77':newTalk}">
          <div v-if="showBottomIcon" @click="scrollToBottom"
               class="scroll_bottom_icon transition_ease"
          ></div>
          <div class="file_list" :class="{'file_list_more':fileList.length>0 || uploadFileLoading}">
            <div @click="showFileDrawer(item)" class="file_item shou relative" v-for="(item,index) in fileList" :key="index">
              <img @click.stop="delFile(item,index)" class="del_icon" src="@/assets/image_ai/del_icon.png" alt="">
              <img class="icon" :src="item.icon" alt="">
              <div class="item_right">
                <div class="name overTxt">{{ item.name }}</div>
                <div class="size">{{ item.sizeText }}</div>
              </div>
            </div>
            <div class="file_item" v-if="uploadFileLoading">
              <img class="file_item_loading" src="@/assets/image_ai/loading_green.png" alt="">
              <div class="item_right">
                <div class="size">等待识别中...</div>
              </div>
            </div>
          </div>
          <el-input
            :disabled="sendLoading"
            @keydown.native="handleKeydown"
            @focus="inputFocus"
            @blur="showBorder = false"
            class="ipt_input"
            :autosize="{
              minRows: 2,
              maxRows: 6
            }"
            resize="none"
            type="textarea"
            placeholder="你好，你可以问元元一些事情"
            v-model="sendValue"
          >
          </el-input>
          <div class="right_bottom">
            <div class="left">
              <div @click="changeState('thinkStatus')" class="btn_item" :class="{'select_status':thinkStatus}">
                <img
                  :src="thinkStatus ? require('@/assets/image_ai/deep_think_act.png') : require('@/assets/image_ai/deep_think.png')"
                  alt="加载失败"
                >
                深度思考
              </div>
              <div @click="changeState('onlineStatus')" class="btn_item" :class="{'select_status':onlineStatus}">
                <img
                  :src="onlineStatus ? require('@/assets/image_ai/it_online_act.png') : require('@/assets/image_ai/it_online.png')"
                  alt="加载失败"
                >
                联网搜索
              </div>
            </div>
            <div class="right">
              <img @click="showFormula" class="icon_btn" src="@/assets/image_ai/formula_icon.png" alt="">
              <img @click="uploadFile(1)" class="icon_btn" src="@/assets/image_ai/img_icon.png" alt="">
              <img @click="uploadFile(2)" class="icon_btn" src="@/assets/image_ai/link_icon.png" alt="">

              <div v-if="!sendLoading">
                <el-tooltip v-if="!sendValue" class="item" v-model="showToolTip" effect="dark" content="请输入你的问题"
                            placement="top"
                >
                  <img class="icon_btn disabled ml_20" src="@/assets/image_ai/send_icon.png" alt="">
                </el-tooltip>
                <img @click="sendMessage" v-if="sendValue" class="icon_btn ml_20"
                     src="@/assets/image_ai/send_act_icon.png" alt=""
                >
              </div>
              <img v-else @click="stopStream" class="icon_btn ml_20" src="@/assets/image_ai/stop_send_icon.png"
                   alt=""
              >
            </div>
          </div>
        </div>
      </div>
      <!--  文件上传    -->
      <input type="file" :accept="accept" ref="fileInput" @change="chooseFile($event.target)" style="display: none">
      <FormulaDialog :show.sync="showFormulaOpen" @formulaReturn="formulaReturn"></FormulaDialog>
      <!--  文件预览    -->
      <fileDrawer
        :show.sync="drawer"
        :url="drawerurl"
        :name="drawername"
        :type="drawertype"
      ></fileDrawer>
    </div>
  </el-drawer>
</template>

<script>
import { returnIcon, returnSize } from '@/utils/util'
import Cookies from 'js-cookie'
import { v4 as uuidv4 } from 'uuid'
import { uploadOSS } from '@/api/upload'
import {
  addConversationApi,
  deleteFileForConversationApi,
  delStreamApi,
  getConversationListApi,
  getCourseHelperListApi,
  getDashscopeHistoryApi,
  refreshStreamApi,
  saveConversationApi,
  sendStreamMessageApi,
  sortConversationListApi,
  sortCourseHelperListApi,
  stopStreamApi,
  uploadFileForConversationApi,
  uploadImageForConversationApi
} from '@/api/tongyi/tongyi'
import ws from '@/plugins/websocket'
import FormulaDialog from '../FormulaDialog/FormulaDialog'
import vuedraggable from 'vuedraggable'

export default {
  name: 'app',
  components: {
    FormulaDialog, vuedraggable
  },
  data() {
    return {
      //文件预览
      drawer: false,
      drawerurl: '',
      drawername: '',
      drawertype: 1,
      //文件上传接受的所有类型
      accept: '*',
      //上传文件的类型，1表示图片上传，2表示文件上传
      uploadType: 1,
      //文件列表，存储已上传的文件信息
      fileList: [],
      //对话列表，存储所有的对话记录
      conversationList: [],
      //课程助手列表，存储与课程相关的助手信息
      courseHelperList: [],
      //消息列表，存储当前对话的消息记录
      messageList: [],
      //当前对话的ID，用于标识不同的对话
      conversationId: null,
      //课程ID，用于对话时判断是否要携带课程id
      courseId: null,
      //对话加载状态，true表示正在加载
      talkLoading: false,
      //显示对话列表的加载状态
      showConversationLoading: false,
      //显示课程列表的加载状态
      showCourseLoading: false,
      //是否显示底部图标，true表示显示
      showBottomIcon: false,
      //深度思考
      thinkStatus: false,
      //联网搜索
      onlineStatus: false,
      //发送按钮的加载状态
      sendLoading: false,
      //新对话的标志，true表示是新对话
      newTalk: true,
      //是否显示工具提示，true表示显示
      showToolTip: false,
      //是否显示边框，true表示显示
      showBorder: false,
      //显示深度思考消息的加载状态
      showReasonLoading: false,
      //上传文件的加载状态，true表示正在加载
      uploadFileLoading: false,
      //第一次接收到stream流的加载状态，true表示正在加载
      firstTalkLoading: false,
      //是否自动滚动，true表示自动滚动
      autoScroll: true,
      //发送消息的值
      sendValue: '',
      //对话的标题
      talkTitle: '当前对话',
      //AI助手项，存储助手的消息内容和其他相关信息
      assistantItem: {
        content: '',
        contents: null,
        name: null,
        reasoningContent: '',
        role: 'assistant',
        searchResults: '',
        toolCallId: null,
        toolCalls: null
      },
      //是否收起侧边列表 true表示收起
      showTextBoolean: false,
      //常用工具展开收起状态 true表示收起
      showToolsBoolean: false,
      //课程列表展开收起状态 true表示收起
      showCourseListBoolean: false,
      //对话列表展开收起状态 true表示收起
      showOtherListBoolean: false,
      //公式状态 true表示打开
      showFormulaOpen: false,
      //常用工具按钮集合
      btns: [
        // {
        //   id: 1,
        //   url:'',
        //   title: '视频转码',
        //   icon: require('@/assets/image_ai/video_icon.png')
        // },
        {
          id: 2,
          url: 'https://translate.volcengine.com/',
          title: '翻译',
          icon: require('@/assets/image_ai/translation_icon.png')
        }
        // {
        //   id: 3,
        //   url:'',
        //   title: '文字识别',
        //   icon: require('@/assets/image_ai/text_icon.png')
        // }
      ]
    }
  },
  props: {
    show: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    dateRange() {
      let { showToolsBoolean, showCourseListBoolean, showOtherListBoolean } = this
      return { showToolsBoolean, showCourseListBoolean, showOtherListBoolean }
    }
  },
  watch: {
    sendValue(val) {
      if (val) {
        this.showToolTip = false
      }
    },
    dateRange: {
      handler() {
        let aiState = {
          showToolsBoolean: this.showToolsBoolean,
          showCourseListBoolean: this.showCourseListBoolean,
          showOtherListBoolean: this.showOtherListBoolean
        }
        Cookies.set('AiState', JSON.stringify(aiState))
      },
      deep: true
    },
    show(val) {
      if (val) {
        let aiState = Cookies.get('AiState')
        if (aiState) {
          let state = JSON.parse(aiState)
          this.showToolsBoolean = state.showToolsBoolean
          this.showCourseListBoolean = state.showCourseListBoolean
          this.showOtherListBoolean = state.showOtherListBoolean
        }
        this.initState()
        this.conversationId = uuidv4().replace(/-/g, '')
        this.initWebSocket()
        this.getConversationList()
        this.getCourseHelperList()
      } else {
        this.drawer = false
        ws.disconnect()
      }
    }
  },
  beforeDestroy() {
    ws.disconnect()
  },
  mounted() {
    if(this.$store.getters.roleId!='teacher'){
      this.showCourseListBoolean = true
    }
  },
  methods: {
    async refreshTalk(item, index) {
      this.messageList.splice(index, 1)
      this.sendLoading = true
      this.firstTalkLoading = true
      try {
        let res = await refreshStreamApi(this.conversationId)
        const { code } = res
        if (code == 200) {
          console.log('刷新成功')
        }
      } catch (e) {
        console.error(e)
      }
    },
    async copyText(item) {
      const textToCopy = item.content
      try {
        await navigator.clipboard.writeText(textToCopy)
        this.$modal.notifySuccess('复制成功')
        // 可以在这里添加提示，如 Toast 或 alert
      } catch (err) {
        console.error('复制失败:', err)
      }
    },
    async handleChange(e, type) {
      if (type == 1) {
        let courseIds = []
        this.courseHelperList.forEach((item) => {
          courseIds.unshift(item.courseId)
        })
        try {
          let res = await sortCourseHelperListApi(courseIds.join(','))
          const { code } = res
          if (code == 200) {
            console.log('排序成功')
          }
        } catch (e) {
          console.error(e)
        }
      } else {
        let conversationIds = []
        this.conversationList.forEach((item) => {
          conversationIds.unshift(item.conversationId)
        })
        try {
          let res = await sortConversationListApi(conversationIds)
          const { code } = res
          if (code == 200) {
            console.log('排序成功')
          }
        } catch (e) {
          console.error(e)
        }
      }
    },
    showFileDrawer(item) {
      this.drawer = true
      this.drawerurl = item.imgUrl
      this.drawername = item.name
    },
    routeTo(item) {
      if (item.url) {
        window.open(item.url)
      }
    },
    async formulaReturn(e) {
      this.sendValue += e
    },
    showFormula() {
      this.showFormulaOpen = true
    },
    changeName(item) {
      item.showRename = true
      this.$nextTick(() => {
        this.$refs.renameRef[0].focus()
      })
    },
    saveName(item) {
      item.showRename = false
      if (item.rename == item.title) {
        return
      }
      this.saveConversation(item)
    },
    // 重命名
    async saveConversation(item) {
      try {
        let params = {
          conversationId: this.conversationId,
          title: item.rename
        }
        if (this.courseId) {
          params.courseId = this.courseId
        }
        let res = await saveConversationApi(params)
        const { code } = res
        if (code == 200) {
          this.$modal.msgSuccess('保存成功')
          this.talkTitle = item.rename
          item.title = item.rename
        }
      } catch (e) {
        console.error(e)
      }
    },
    //  停止对话
    async stopStream() {
      try {
        let res = await stopStreamApi(this.conversationId)
        const { code } = res
        if (code == 200) {
          console.log('停止对话成功')
        }
      } catch (e) {
        console.error(e)
      }
    },
    //  删除对话
    async delStream(item) {
      this.$confirm(`确定要删除【${item.title}】对话吗？`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async() => {
        const loading = this.$loading({
          lock: true,
          text: '正在处理...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.3)'
        })
        try {
          let params = {
            conversationId: item.conversationId
          }
          let res = await delStreamApi(params)
          if (res.code == 200) {
            this.$modal.msgSuccess('删除成功')
            if (item.conversationId == this.conversationId) {
              this.messageList = []
            }
            this.newTalk = true
            this.getConversationList()
          }
        } catch (e) {
          console.error(e)
        } finally {
          loading.close()
        }
      }).catch(() => {
        this.$modal.msgInfo('已取消')
      })
    },
    // 初始化状态
    initState() {
      this.sendLoading = false
      this.newTalk = true
      this.showToolTip = false
      this.showBottomIcon = false
      this.sendValue = ''
      this.messageList = []
      this.fileList = []
      this.assistantItem = {
        content: '',
        contents: null,
        name: null,
        reasoningContent: '',
        role: 'assistant',
        searchResults: '',
        toolCallId: null,
        toolCalls: null
      }
    },
    getMaxSortValue(arr) {
      if (!arr || arr.length === 0) {
        return 0
      }
      return Math.max(...arr.map(item => item.sort))
    },
    // 新增会话
    async addConversation(sendValue) {
      try {
        let params = {
          conversationId: this.conversationId,
          title: sendValue,
          userId: this.$store.getters.userId
        }
        let maxSort = 0
        if (this.courseId) {
          params.courseId = this.courseId
          params.sort = 2
          maxSort = this.getMaxSortValue(this.courseHelperList)
          console.log('maxSort_courseId', maxSort)
          params.sort = maxSort + 1
        } else {
          maxSort = this.getMaxSortValue(this.conversationList)
          console.log('maxSort_conversation', maxSort)
          params.sort = maxSort + 1
        }
        let res = await addConversationApi(params)
        const { code } = res
        if (code == 200) {
          //非课程列表需要添加对话到列表中
          if (!this.courseId) {
            //前端手动添加对话至左边列表
            let obj = {
              conversationId: this.conversationId,
              userId: this.$store.getters.userId,
              sort: maxSort + 1,
              rename: sendValue,
              showRename: false,
              title: sendValue
            }
            this.conversationList.unshift(obj)
          }
          //前端手动添加对话内容至聊天列表
          let msg = {
            content: this.sendValue,
            contents: null,
            name: null,
            reasoningContent: '',
            role: 'user',
            searchResults: '',
            toolCallId: null,
            toolCalls: null
          }
          if (this.fileList.length > 0) {
            msg.sendFileList = this.fileList
            this.fileList = []
          }
          this.messageList.push(msg)
          this.newTalk = false
          //发起对话请求
          let params = {
            content: sendValue,
            conversationId: this.conversationId,
            deepThinking: this.thinkStatus,
            internetSearch: this.onlineStatus,
            filePath: '',
            userId: this.$store.getters.userId
          }
          this.sendStreamMessage(params)
          this.sendValue = '' // 清空输入框
        }
      } catch (e) {
        console.log(e)
      }
    },
    // 初始化websocket
    initWebSocket() {
      let hostname = window.location.hostname
      const local = hostname === 'localhost' || /^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) ? 'ws://' + hostname + ':9208' : 'wss://' + hostname+ '/cloud'
      let url = local + `/ws/conversationWS/${this.$store.getters.userId}/${this.conversationId}`
      ws.connect(url, this.handleMessage, false, false)
    },
    //  接收服务器推送的信息
    handleMessage(data) {
      console.log('接收服务器推送的信息>>>>>>>>', data)
      if (data && this.firstTalkLoading) {
        this.firstTalkLoading = false
      }
      if (data == 'DialogueConflict') {
        this.handleClose()
        this.$confirm(`您的AI功能正在其他设备使用，继续使用需要重新打开，请注意账号安全`, 'AI关闭通知', {
          confirmButtonText: '重新打开',
          type: 'warning'
        }).then(() => {
          this.$emit('update:show', true)
        }).catch(() => {
          this.handleClose()
        })
        return
      }
      // 对话结束标志
      if (data == 'ConversationMessageCompleted') {
        this.messageList.forEach((value) => {
          if (value.role == 'assistant') {
            value.content = this.formaterContent(value.content)
            if (value.reasoningContent) {
              value.reasoningContent = value.reasoningContent.replace(/\[ref_(\d+)\]/g, '<a href="#ref_$1">[$1]</a>')
            }
          }
        })
        this.assistantItem = {
          content: '',
          contents: null,
          name: null,
          reasoningContent: '',
          role: 'assistant',
          searchResults: '',
          toolCallId: null,
          toolCalls: null
        }
        this.sendLoading = false
        return
      }

      // 实时格式化内容
      let formattedData = data
      if (data.includes('content:')) {
        let content = data.split('content:')[1]
        formattedData = 'content:' + this.formaterContent(content)
      }

      let lastIndex = this.messageList.length - 1
      if (this.messageList[lastIndex]?.role == 'user') {
        if (formattedData.includes('content:')) {
          if (this.showReasonLoading) {
            this.showReasonLoading = false
          }
          let content = formattedData.split('content:')[1]
          this.assistantItem.content += content
        }
        if (formattedData.includes('search:')) {
          let search = formattedData.split('search:')[1]
          this.assistantItem.searchResults = JSON.parse(search)
        }
        if (formattedData.includes('reason:')) {
          if (!this.showReasonLoading) {
            this.showReasonLoading = true
          }
          let reason = formattedData.split('reason:')[1]
          this.assistantItem.reasoningContent += reason
        }
        this.messageList.push(this.assistantItem)
      } else {
        if (formattedData.includes('content:')) {
          if (this.showReasonLoading) {
            this.showReasonLoading = false
          }
          let content = formattedData.split('content:')[1]
          this.messageList[lastIndex].content += content
        }
        if (formattedData.includes('search:')) {
          let search = formattedData.split('search:')[1]
          this.messageList[lastIndex].searchResults = JSON.parse(search)
        }
        if (formattedData.includes('reason:')) {
          if (!this.showReasonLoading) {
            this.showReasonLoading = true
          }
          let reason = formattedData.split('reason:')[1]
          this.messageList[lastIndex].reasoningContent += reason
        }
      }

      this.$nextTick(() => {
        this.scrollToBottom()
      })
    },
    scrollToBottom(force = false) {
      if (force || this.autoScroll) {
        this.$nextTick(() => {
          const container = this.$refs.chatBox
          if (container) {
            // 直接赋值（兼容性好）
            container.scrollTop = container.scrollHeight
          }
        })
      }
    },
    //发送消息接口
    async sendStreamMessage(params) {
      try {
        let res = await sendStreamMessageApi(params)
        const { code } = res
        console.log(code, '消息发送成功')
      } catch (e) {
        console.log(e)
      }
    },
    resetState(){
      this.sendValue = ''
      this.showBottomIcon = false
      this.sendLoading = false
      this.firstTalkLoading = false
      this.messageList = []
      this.fileList = []
      ws.disconnect()
    },
    //点击开启新对话
    handleClickNewTalk() {
      this.talkTitle = '当前对话'
      this.courseId = null
      this.resetState()
      //前端生成conversationId
      this.conversationId = uuidv4().replace(/-/g, '')
      //开启新的websocket
      this.initWebSocket()
      //新对话状态置为true
      this.newTalk = true
    },
    //点击课程列表切换会话
    handleClickCourseItem(item) {
      this.courseId = item.courseId
      if (item.conversationId === this.conversationId) {
        return
      }
      this.resetState()
      if (!item.conversationId) {
        this.newTalk = true
        let uuid = uuidv4().replace(/-/g, '')
        item.conversationId = uuid
        this.conversationId = uuid
        //初始化websocket
        this.initWebSocket()
      } else {
        this.conversationId = item.conversationId
        this.initWebSocket()
        this.getDashscopeHistory(true)
      }
    },
    //点击对话列表切换会话
    handleClick(item) {
      if (item.conversationId === this.conversationId) {
        return
      }
      this.resetState()
      this.courseId = null
      //新的conversationId
      this.conversationId = item.conversationId
      this.newTalk = false
      //初始化websocket
      this.initWebSocket()
      //获取历史记录
      this.getDashscopeHistory(false)
    },
    //获取会话列表
    async getConversationList() {
      this.showConversationLoading = true
      try {
        let res = await getConversationListApi()
        const { code, data } = res
        if (code == 200) {
          for (const datum of data) {
            datum.rename = datum.title
            datum.showRename = false
          }
          data.sort((a, b) => (b.sort || 0) - (a.sort || 0))
          this.conversationList = data
        }
      } catch (e) {
        console.log(e)
      } finally {
        this.showConversationLoading = false
      }
    },
    // 获取课程助手列表
    async getCourseHelperList() {
      this.showCourseLoading = true
      try {
        let res = await getCourseHelperListApi()
        const { code, data } = res
        if (code == 200) {
          data.sort((a, b) => (b.sort || 0) - (a.sort || 0))
          this.courseHelperList = data
        }
      } catch (e) {
        console.log(e)
      } finally {
        this.showCourseLoading = false
      }
    },
    //获取历史记录
    async getDashscopeHistory(check) {
      this.talkLoading = true
      try {
        let params = {
          conversationId: this.conversationId
        }
        let res = await getDashscopeHistoryApi(params)
        const { code, data } = res
        if (code == 200) {
          if (check && data.messageList.length == 0) {
            this.newTalk = true
            return
          }
          if (this.newTalk) {
            this.newTalk = false
          }
          data.messageList.forEach((value) => {
            if (value.role == 'assistant') {
              value.content = this.formaterContent(value.content)
              if (value.searchResults) {
                for (const valueElement of value.searchResults) {
                  valueElement.site_name = valueElement.siteName
                }
              }
              if (value.reasoningContent) {
                value.reasoningContent = value.reasoningContent.replace(/\[ref_(\d+)]/g, '<a href="#ref_$1">[$1]</a>')
              }
            }
            if (value.role == 'user') {
              if (value.fileList) {
                let arr = []
                for (const filePathListElement of value.fileList) {
                  let obj = {
                    icon: returnIcon(filePathListElement.cdnPath, 1),
                    name: filePathListElement.fileName,
                    imgUrl: filePathListElement.cdnPath,
                    sizeText: filePathListElement.size
                  }
                  arr.push(obj)
                }
                value.sendFileList = arr
              }
            }
          })
          this.messageList = data.messageList
          this.talkTitle = data.title
          this.$nextTick(() => {
            this.scrollToBottom()
          })
        }
      } catch (e) {
        console.log(e)
      } finally {
        this.talkLoading = false
      }
    },
    // 删除文件
    async delFile(item, index) {
      const loading = this.$loading({
        lock: true,
        text: '正在删除文件',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.3)'
      })
      try {
        let res = await deleteFileForConversationApi(this.conversationId, item.fileId)
        const { code } = res
        if (code == 200) {
          this.fileList.splice(index, 1)
        }
      } catch (e) {
        console.error(e)
      } finally {
        loading.close()
      }
    },
    //  上传文件
    uploadFile(type) {
      this.uploadType = type
      this.accept = type == 1 ? 'image/*' : '.doc,.docx,.ppt,.pptx,.xls,.xlsx,.pdf,.txt'
      this.$nextTick(() => {
        this.$refs.fileInput.click()
      })
    },
    // 选择文件
    async chooseFile(event) {
      const file = this.$refs.fileInput.files[0]
      let obj = {
        icon: returnIcon(file.name, 1),
        name: file.name,
        size: file.size,
        sizeText: returnSize(file.size),
        type: file.type,
        file: file
      }
      let result = await uploadOSS(file, 'ai')
      if (this.uploadType == 1) {
        const isImageValid = await new Promise((resolve) => {
          const img = new Image()
          img.onload = () => {
            URL.revokeObjectURL(img.src) // 释放内存
            resolve(img.width > 10 && img.height > 10)
          }
          img.onerror = () => {
            URL.revokeObjectURL(img.src) // 释放内存
            resolve(false)
          }
          img.src = URL.createObjectURL(file)
        })
        if (!isImageValid) {
          this.$modal.msgWarning('图片尺寸必须大于10x10像素')
          event.target.value = '' // 清空文件选择
          return
        }
        obj.imgUrl = result[0]
        this.uploadFileLoading = true
        let params = {
          cdnPath: obj.imgUrl,
          filePath: obj.imgUrl.replace('https://oss.metaxun.com', 'https://hgcc-metaxun.oss-cn-hangzhou.aliyuncs.com'),
          fileName: obj.name,
          size: obj.sizeText
        }
        try {
          let res = await uploadImageForConversationApi(this.conversationId, params)
          const { code, msg } = res
          if (code == 200) {
            obj.fileId = msg
          }
        } catch (e) {
          console.error(e)
        } finally {
          this.uploadFileLoading = false
        }
      } else {
        let formData = new FormData()
        formData.append('file', file)
        this.uploadFileLoading = true
        obj.imgUrl = result[0]
        try {
          let res = await uploadFileForConversationApi(this.conversationId, formData)
          const { code, msg } = res
          if (code == 200) {
            obj.fileId = msg
          }
        } catch (e) {
          console.error(e)
        } finally {
          this.uploadFileLoading = false
        }
      }
      this.fileList.push(obj)
      event.value = ''
    },
    //  滚动条处理
    handleChatBoxScroll() {
      const container = this.$refs.chatBox
      if (!container) return
      // 判断是否接近底部（20px 缓冲）
      const isNearBottom =
        container.scrollTop + container.clientHeight >=
        container.scrollHeight - 20

      this.autoScroll = isNearBottom
      this.showBottomIcon = !isNearBottom
    },
    //  输入框聚焦  滚动底部
    inputFocus() {
      this.showBorder = true
      this.scrollToBottom(true)
    },
    //  滚动到指定锚点
    scrollToAnchor(id) {
      const anchor = document.getElementById(id)
      if (anchor) {
        anchor.scrollIntoView({ behavior: 'smooth' })
      }
    },
    // 输入框失焦
    handleKeydown(event) {
      if (event.key === 'Enter' && !event.shiftKey) {
        event.preventDefault() // 阻止默认的换行行为
        this.sendMessage() // 调用发送消息的方法
      }
    },
    //  发送消息
    sendMessage() {
      // 防连点：如果正在发送中，直接返回
      if (this.sendLoading) {
        return
      }
      // 判断输入框是否为空
      if (!this.sendValue) {
        this.showToolTip = true
        return
      }
      // 设置发送状态为true防止连点
      this.sendLoading = true
      this.scrollToBottom()
      //新对话发送 先创建对话再发送消息
      if (this.newTalk) {
        // 发送消息的逻辑
        this.addConversation(this.sendValue)
      } else {
        //直接发送消息
        let msg = {
          content: this.sendValue,
          contents: null,
          name: null,
          reasoningContent: null,
          role: 'user',
          searchResults: null,
          toolCallId: null,
          toolCalls: null
        }
        if (this.fileList.length > 0) {
          msg.sendFileList = this.fileList
          this.fileList = []
        }
        this.messageList.push(msg)
        //发送消息接口
        let params = {
          content: this.sendValue,
          conversationId: this.conversationId,
          deepThinking: this.thinkStatus,
          internetSearch: this.onlineStatus,
          filePath: '',
          userId: this.$store.getters.userId
        }
        this.sendStreamMessage(params)
        this.sendValue = '' // 清空输入框
      }
      this.firstTalkLoading = true
    },
    formaterContent(content) {
      // 1. 替换 '###' 和 '####' 为空字符串
      let result = content.replace(/(####|###)/g, '')

      // 2. 处理 ``` 代码块，替换为加粗标签
      result = result.replace(/```([^`]+)```/g, '$1')

      // 3. 处理 ** 加粗文本
      result = result.replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>')

      // 4. 替换 --- 为横线标签（使用）
      result = result.replace(/---/g, '')

      // 5. 处理 - 开头的行，替换为无序列表
      result = result.replace(/^(-\s)(.*)$/gm, '$2')

      // 6. 处理 * 开头的行，替换为无序列表
      result = result.replace(/^\*(\s)(.*)$/gm, '$2')

      // 7. 处理 1. 开头的行，替换为有序列表
      result = result.replace(/^(\d+\.\s)(.*)$/gm, '$2')

      // 8. 处理 # 开头的行，替换为标题标签
      result = result.replace(/^# (.*)$/gm, '$1')
      result = result.replace(/^## (.*)$/gm, '$1')
      result = result.replace(/^### (.*)$/gm, '$1')
      result = result.replace(/^#### (.*)$/gm, '$1')
      result = result.replace(/^##### (.*)$/gm, '$1')
      result = result.replace(/^###### (.*)$/gm, '$1')

      // 9. 处理 > 引用
      result = result.replace(/^>(.*)$/gm, '$1')

      // 10. 处理链接
      result = result.replace(/(https?:\/\/[^\s]+)/g, '$1')

      // 11. 处理表格
      result = result.replace(/\|(.+)\|\n\|-+-(\n\|.+\|)+/g, (match, headers, separator, rows) => {
        const headerCells = headers.split('|').map(h => h.trim()).filter(Boolean)
        const rowCells = rows.split('\n').map(r => r.split('|').map(c => c.trim()).filter(Boolean))
        const tableHtml = rowCells.reduce((html, row) => html + `${row.map(cell => `${cell}`).join('')}`, '')
        return `${headerCells.map(() => ``).join('')}${tableHtml}${header}`
      })

      // 12. 处理缩进代码块
      result = result.replace(/^ {4}(.+)/gm, '$1')
      // 处理引用
      result = result.replace(/\[ref_(\d+)]/g, '<a href="#ref_$1">[$1]</a>')

      return result
    },
    changeState(key) {
      this[key] = !this[key]
    },
    handleClose() {
      this.$emit('update:show', false)
    }
  }
}
</script>

<style scoped lang="scss">
.components_container {
  width: 100%;
  height: 100vh;
  overflow: hidden;
  background-image: url("../../assets/image_ai/AI_BG.png");
  background-size: cover;
  display: flex;

  .el-icon-close {
    cursor: pointer;
    top: 20px;
    right: 20px;
    position: absolute;
    z-index: 999;
    font-size: 24px;
  }

  .talk_left {
    width: 260px;
    height: 100%;
    overflow: hidden;
    padding: 30px 12px 24px 16px;
    box-sizing: border-box;
    border: 1px solid #EAEDF5;
    display: flex;
    flex-direction: column;
    justify-content: space-between;

    .top {
      .ai_name {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: space-between;
        user-select: none;

        .title {
          width: 100px;
          height: 34px;
          overflow: hidden;
          font-family: PingFangSC, PingFang SC, sans-serif;
          font-weight: 600;
          font-size: 24px;
          color: #333333;
        }

        .close_icon {
          width: 32px;
          height: 32px;
          cursor: pointer;
        }

      }

      .course_collect {
        margin-top: 24px;
        display: flex;
        flex-direction: column;

        .other_talk {
          padding: 0 8px 0 20px;
          box-sizing: border-box;
          overflow-y: auto;
          display: flex;
          flex-direction: column;
          gap: 6px 0;

          .talk_item {
            width: 100%;
            padding: 9px 7px 9px 12px;
            box-sizing: border-box;
            border-radius: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            user-select: none;
            cursor: pointer;

            .talk_name {
              width: 168px;
              font-family: PingFangSC, PingFang SC, sans-serif;
              font-weight: 400;
              font-size: 16px;
              color: #333333;
            }

            .rename_ipt_content {
              width: 100%;

              .rename_ipt {
                width: 100%;

                ::v-deep .el-input__inner {
                  border-radius: 8px !important;
                  height: 42px !important;
                  border: 2px solid #28b28b;
                }
              }
            }

            .btn {
              width: 16px;
              height: 16px;

              .del_icon {
                width: 16px;
                height: 16px;
                display: none;
              }
            }

            &:hover {
              background: #EEF3FA;

              .btn {
                .del_icon {
                  display: block;
                }
              }
            }
          }

          .empty_box {
            padding-top: 20px;
            box-sizing: border-box;
            display: flex;
            justify-content: center;
            font-size: 14px;
            font-weight: 500;
            color: #8b8b8b;
          }
        }

        .course_talk_list {
          padding: 0 6px 0 20px;
          box-sizing: border-box;
          overflow-y: auto;
          display: flex;
          flex-direction: column;
          gap: 6px 0;

          .talk_item {
            width: 100%;
            padding: 9px 7px 9px 12px;
            box-sizing: border-box;
            border-radius: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            user-select: none;
            cursor: pointer;

            .talk_name {
              width: 168px;
              font-family: PingFangSC, PingFang SC, sans-serif;
              font-weight: 400;
              font-size: 16px;
              color: #333333;
            }

            .btn {
              width: 16px;
              height: 16px;

              .del_icon {
                width: 16px;
                height: 16px;
                display: none;
              }
            }

            &:hover {
              background: #EEF3FA;

              .btn {
                .del_icon {
                  display: block;
                }
              }
            }
          }
        }
      }
    }

    .bottom {
      width: 100%;

      .tools_btns {
        margin-top: 15px;
        padding: 0 2px;
        box-sizing: border-box;
        width: 100%;
        display: flex;
        justify-content: space-between;
        align-items: center;
        overflow: hidden;
        height: 66px;

        .item_btn {
          width: 72px;
          height: 66px;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          font-family: PingFangSC, PingFang SC, sans-serif;
          font-weight: 400;
          font-size: 14px;
          color: #333333;
          background: #FFFFFF;
          border-radius: 8px;
          border: 1px solid #EBEBEB;
          user-select: none;
          cursor: pointer;

          img {
            width: 16px;
            height: 16px;
            margin-bottom: 10px;
          }

          &:hover {
            background: #EEF3FA;
            border: 1px solid #EEF3FA;
          }

          &:active {
            background: #e6e9ec;
            border: 1px solid #e6e9ec;
          }
        }
      }
    }
  }

  .talk_right {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 32px 0 24px;
    box-sizing: border-box;
    transition: all 0.3s ease;

    .say_hello {
      font-family: PingFangSC, PingFang SC, sans-serif;
      font-weight: 500;
      height: 46px;
      font-size: 32px;
      color: #333333;
    }

    .talk_title {
      max-width: 900px;
      font-family: PingFangSC, PingFang SC, sans-serif;
      font-weight: 600;
      font-size: 18px;
      color: #333333;
    }

    .talk_content {
      width: 100%;
      flex: 1;
      overflow-y: auto;
      padding: 0 104px;
      box-sizing: border-box;
      display: flex;
      flex-direction: column;
      margin-top: 40px;
      gap: 33px 0;

      &::-webkit-scrollbar {
        width: 8px;
      }

      &::-webkit-scrollbar-thumb {
        background: #dbdee0;
        border-radius: 10px;
      }

      &::-webkit-scrollbar-track {
        background: transparent;
      }

      .user_chat {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: flex-end;

        .send_file_list {
          max-width: 100%;
          display: flex;
          flex-wrap: wrap;
          gap: 12px;
          margin-bottom: 16px;

          .file_item {
            width: 224px;
            height: 58px;
            background: #F5F5F5;
            border-radius: 8px;
            display: flex;
            align-items: center;
            padding: 9px 9px 9px 12px;
            box-sizing: border-box;

            &:hover {
              .del_icon {
                display: block;
              }
            }

            .del_icon {
              width: 16px;
              height: 16px;
              position: absolute;
              top: -6px;
              right: -6px;
              display: none;
              z-index: 99;
              cursor: pointer;
            }

            .icon {
              width: 40px;
              height: 40px;
              border-radius: 4px;
              margin-right: 10px;
            }

            .item_right {
              flex: 1;

              .name {
                width: 154px;
                font-family: PingFangSC, PingFang SC, sans-serif;
                font-weight: 400;
                font-size: 14px;
                color: #333333;
              }

              .size {
                font-family: PingFangSC, PingFang SC, sans-serif;
                font-weight: 400;
                font-size: 14px;
                color: #999999;
                line-height: 20px;
              }
            }
          }
        }

        .user_content {
          max-width: calc(100% - 56px);
          padding: 9px 16px;
          box-sizing: border-box;
          background: #28B28B;
          border-radius: 8px;
          font-family: PingFangSC, PingFang SC, sans-serif;
          font-weight: 400;
          font-size: 18px;
          color: #FFFFFF;
        }
      }

      .ai_chat {
        width: 100%;
        display: flex;
        justify-content: flex-start;

        .ai_avatar {
          width: 40px;
          height: 33px;
          margin-right: 16px;
        }

        .ai_content {
          max-width: 100%;
          padding: 9px 16px;
          box-sizing: border-box;
          background: #EEF3FA;
          border-radius: 8px;
          font-family: PingFangSC, PingFang SC, sans-serif;

          .online_search {
            display: flex;
            flex-direction: column;
            align-items: flex-start;

            .title {
              padding: 6px 10px;
              font-size: 14px;
              margin-bottom: 16px;
              box-sizing: border-box;
              background: #34b692;
              border-radius: 10px;
              color: #FFFFFF;
            }

            .search_item {
              display: flex;
              flex-direction: column;
              box-sizing: border-box;
              transition: all 0.3s ease;
              margin-bottom: 4px;
              padding: 2px 12px 6px 0;

              &:hover {
                background: rgba(52, 182, 146, 0.1);
                border-radius: 6px;
                padding-left: 12px;
              }

              .top {
                display: flex;
                align-items: center;
                color: #333333;
                font-size: 16px;
                font-weight: bold;

                img {
                  width: 14px;
                  height: 14px;
                  object-fit: cover;
                  margin-right: 12px;
                }
              }

              .text {
                color: #999999;
                font-size: 14px;
                font-weight: 500;
              }
            }
          }

          .deep_thinking {
            width: 100%;
            display: flex;
            flex-direction: column;
            align-items: flex-start;

            .loading_title {
              padding: 6px 10px;
              font-size: 14px;
              margin: 16px 0;
              box-sizing: border-box;
              background: #34b692;
              border-radius: 10px;
              color: #ffffff;
              display: flex;
              align-items: center;

              .loading_img {
                margin-left: 4px;
                width: 14px;
                height: 14px;
                animation: loading 1s infinite;
              }
            }

            .title {
              padding: 6px 10px;
              font-size: 14px;
              margin: 16px 0;
              box-sizing: border-box;
              border-radius: 10px;
              background: #34b692;
              color: #ffffff;
            }

            .content {
              width: 100%;
              padding: 0 0 0 10px;
              box-sizing: border-box;
              border-left: 1px solid #e5e5e5;
              color: #828282;
              font-size: 16px;
              margin-bottom: 16px;
            }
          }

          .common_text {
            font-weight: 400;
            font-size: 18px;
            color: #333333;

            .loading_img {
              margin-left: 4px;
              width: 14px;
              height: 14px;
              animation: loading 1s infinite;
            }
          }
        }

        .ai_btns {
          margin-top: 8px;
          display: flex;
          gap: 0 8px;
          box-sizing: border-box;

          .ai_copy {
            width: 24px;
            height: 24px;
            border-radius: 4px;
            display: flex;
            justify-content: center;
            align-items: center;
            user-select: none;
            cursor: pointer;

            &:hover {
              background: #eef3fa;
            }

            img {
              width: 16px;
              height: 16px;
            }
          }
        }
      }

      .talk_bottom {
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }

    .ipt_content {
      padding: 6px 0 12px;
      box-sizing: border-box;
      margin-top: 25px;
      width: 632px;
      background: #FFFFFF;
      box-shadow: 0 0 16px 0 rgba(0, 55, 50, 0.08);
      border-radius: 16px;
      border: 1px solid #EBEBEB;

      .file_list {
        width: 100%;
        display: flex;
        flex-wrap: wrap;
        max-height: 146px;
        overflow: auto;
        gap: 12px;

        &::-webkit-scrollbar {
          width: 2px;
        }

        &::-webkit-scrollbar-thumb {
          background: #e1e1e1;
          border-radius: 2px;
        }

        .file_item {
          width: 224px;
          height: 58px;
          background: #F5F5F5;
          border-radius: 8px;
          display: flex;
          align-items: center;
          padding: 9px 9px 9px 12px;
          box-sizing: border-box;

          &:hover {
            .del_icon {
              display: block;
            }
          }

          .del_icon {
            width: 16px;
            height: 16px;
            position: absolute;
            top: -6px;
            right: -6px;
            display: none;
            z-index: 99;
            cursor: pointer;
          }

          .icon {
            width: 40px;
            height: 40px;
            border-radius: 4px;
            margin-right: 10px;
          }

          .item_right {
            flex: 1;

            .name {
              width: 154px;
              font-family: PingFangSC, PingFang SC, sans-serif;
              font-weight: 400;
              font-size: 14px;
              color: #333333;
            }

            .size {
              font-family: PingFangSC, PingFang SC, sans-serif;
              font-weight: 400;
              font-size: 14px;
              color: #999999;
              line-height: 20px;
            }
          }
        }
      }

      .scroll_bottom_icon {
        position: absolute;
        top: -64px;
        right: calc(50% - 32px);
        width: 64px;
        height: 64px;
        border-radius: 50%;
        background-image: url("../../assets/image_ai/scroll_bottom.png");
        background-size: 100% 100%;
        user-select: none;
        cursor: pointer;

        &:hover {
          background-image: url("../../assets/image_ai/scroll_bottom_act.png");
        }
      }

      .ipt_input {
        font-family: PingFangSC, PingFang SC, sans-serif;
        font-weight: 400;
        font-size: 16px;
        color: #999999;
      }

      .right_bottom {
        width: 100%;
        margin-top: 12px;
        padding: 0 12px;
        box-sizing: border-box;
        display: flex;
        justify-content: space-between;

        .left {
          display: flex;
          align-items: center;
          gap: 0 12px;

          .btn_item {
            user-select: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            font-family: PingFangSC, PingFang SC, sans-serif;
            font-weight: 400;
            font-size: 14px;
            color: #666666;
            padding: 6px 8px;
            background: #FFFFFF;
            border-radius: 8px;
            box-sizing: border-box;
            border: 1px solid #EBEBEB;

            img {
              width: 16px;
              height: 16px;
              margin-right: 6px;
            }
          }
        }

        .right {
          display: flex;
          align-items: center;

          .icon_btn {
            width: 32px;
            height: 32px;
            cursor: pointer;
            user-select: none;
          }
        }
      }
    }
  }
}

.tools_container {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
  cursor: pointer;

  .title {
    display: flex;
    align-items: center;
    font-family: PingFangSC, PingFang SC, sans-serif;
    font-weight: 500;
    font-size: 16px;
    color: #333333;

    .icon {
      width: 24px;
      height: 24px;
      margin-right: 8px;
    }
  }

  .right_icon {
    width: 16px;
    height: 16px;
  }
}

.new_talk {
  margin-top: 15px;
  padding: 9px 12px;
  box-sizing: border-box;
  border-radius: 8px;
  display: flex;
  align-items: center;
  user-select: none;
  cursor: pointer;
  background: rgba(155, 244, 219, 0.1);
  border: 1px solid rgba(64, 184, 150, 0.44);

  img {
    width: 16px;
    height: 16px;
    margin-right: 8px;
  }

  .name {
    font-family: PingFangSC, PingFang SC, sans-serif;
    font-weight: 500;
    font-size: 16px;
    color: #28B28B;
  }

  &:hover {
    background: rgba(155, 244, 219, 0.3);
  }

  &:active {
    background: rgba(108, 229, 195, 0.3);
  }

}

@keyframes loading {
  0% {
    transform: rotateZ(0deg);
  }

  100% {
    transform: rotateZ(360deg);
  }
}

.file_list_more {
  padding: 6px 16px 16px;
  border-bottom: 1px solid #E8EAEB;
  box-sizing: border-box;
  margin-bottom: 12px;
}

.file_item_loading {
  width: 30px;
  height: 30px;
  border-radius: 4px;
  margin-right: 10px;
  animation: loading 1s infinite;
}

.select_active {
  background: #EEF3FA !important;
}

::v-deep .el-loading-mask {
  background: linear-gradient(256deg, rgba(255, 255, 255, 0) 0%, #f8fdff 100%);
}

::v-deep .is-disabled .el-textarea__inner {
  background: #FFFFFF !important;
}

::v-deep .el-textarea__inner {
  border: 0;
  padding: 0 12px;
  box-sizing: border-box;
  border-radius: 16px;
}

.mt_12 {
  margin-top: 12px;
}

.ml_20 {
  margin-left: 20px;
}

.mt_6 {
  margin-top: 6px;
}

.w_all {
  width: 100%;
}

.w_63 {
  width: 63px !important;
}

.w_0 {
  width: 0 !important;
}

.h_0 {
  height: 0 !important;
}

.disabled {
  cursor: not-allowed !important;
}

.select_status {
  background: #E8FFF0 !important;
  color: #28B28B !important;
  border: 1px solid #8ADDAD !important;
}

.rotate_z_180 {
  transform: rotateZ(180deg);
}

.border_0 {
  border: 1px solid transparent !important;
}

.border_green {
  border: 1px solid #28B28B !important;
}

.transition_ease {
  transition: all 0.3s ease;
}

.only_height {
  max-height: calc(100vh - 254px) !important;
}

.only_herf_height {
  max-height: calc((100vh - 254px) / 2) !important;
}

.only_height2 {
  max-height: calc(100vh - 314px) !important;
}

.only_herf_height2 {
  max-height: calc((100vh - 314px) / 2) !important;
}

.max_height_0 {
  max-height: 0 !important;
}

.mb_77 {
  margin-bottom: 77px;
}

.custom_ghost {
  background-color: transparent; /* 设置被拖拽元素的背景色为红色 */
}

.max_width {
  max-width: calc(100% - 260px);
}

::v-deep a {
  text-decoration: none;
  font-size: 12px !important;
  color: #6c59f5 !important;
}

.p_0 {
  padding: 0 !important;
}
</style>
